#NoEnv
#include ScreenCapture.ahk

#Include Crypt.ahk
#Include CryptConst.ahk
#Include CryptFoos.ahk

#Include py_socket.ahk

cloud_url := "http://moe-vendor-search.appspot.com/"

str_magic = __cr_magic__%COMPUTERNAME%

CoordMode, Mouse, Screen     ; Make 0,0 the top-left of screen
CoordMode, ToolTip, Screen

CaptureMode := 0

AryJob := {}
job_count := 0
;SetWorkingDir, %A_ScriptDir%
topLeftCoordActive = 1   ; 0 = The top-left coordinate is active; 1 = The bottom-right coordinate is active
moveBothCorners    = 0   ; 1 = Move both corners at the same time
bothCornersHeight  = 0   ; The height of the capture box with in "move both corners" mode
bothCornersWidth   = 0   ; The width of the capture box with in "move both corners" mode
BOX_UPDATE_RATE    = 10  ; The update rate of the capture box (ms)
MONO_FILTER = Utils\b2m32010\BMP2MONO.exe

    ; OCR対象領域の設定をINIファイルから設定を読み込む
    mvinifile = mvcap.ini
    IniRead, x1,                    %mvinifile%, Coord, x1
    IniRead, y1,                    %mvinifile%, Coord, y1
    IniRead, x2,                    %mvinifile%, Coord, x2
    IniRead, y2,                    %mvinifile%, Coord, y2
    IniRead, ChkJpg,                %mvinifile%, Coord, ChkJpg
    IniRead, ChkOCR,                %mvinifile%, Coord, ChkOCR
    IniRead, ChkAppend_OneText,     %mvinifile%, Coord, ChkAppend_OneText
    IniRead, TxtAppend_Filename,    %mvinifile%, Coord, TxtAppend_Filename
    IniRead, ChkAdditionalCap,      %mvinifile%, Coord, ChkAdditionalCap
    IniRead, AddX1,                 %mvinifile%, Coord, AddX1
    IniRead, AddY1,                 %mvinifile%, Coord, AddY1
    IniRead, AddX2,                 %mvinifile%, Coord, AddX2
    IniRead, AddY2,                 %mvinifile%, Coord, AddY2
    IniRead, CapHotkey,             %mvinifile%, Coord, CapHotkey
    IniRead, AdjustX,               %mvinifile%, Coord, AdjustX
    IniRead, Append_HTML,           %mvinifile%, Coord, Append_HTML
    IniRead, Append_BaseDir,        %mvinifile%, Coord, Append_BaseDir
    IniRead, ChkDebug,              %mvinifile%, Coord, ChkDebug
    IniRead, MoE_UserdataDir,       %mvinifile%, Coord, MoE_UserdataDir
    IniRead, Chk_Excel,             %mvinifile%, Coord, Chk_Excel
    IniRead, Excel_Filename,        %mvinifile%, Coord, Excel_Filename
    IniRead, Chk_GoogleSpr,         %mvinifile%, Coord, Chk_GoogleSpr
    IniRead, GoogleSpr_User,        %mvinifile%, Coord, GoogleSpr_User
    IniRead, GoogleSpr_Pass,        %mvinifile%, Coord, GoogleSpr_Pass
    IniRead, GoogleSpr_SheetName,   %mvinifile%, Coord, GoogleSpr_SheetName
    IniRead, Chk_GoogleGAE,         %mvinifile%, Coord, Chk_GoogleGAE

    ; 初回起動の場合、適当に初期値を設定する(じ環境: 解像度1920x1400 推奨設定)。
    mvc_1st_run := 0
    if (!(x1 > 0 && x1 < 2000)) {
        mvc_1st_run := 1
        MsgBox 初回起動です。`nデフォルト設定します。
        x1                  := 900
        y1                  := 30
        x2                  := 1400
        y2                  := 400
        ChkJpg              := 1
        ChkOCR              := 0
        ChkAppend_OneText   := 1
        TxtAppend_Filename   = mvcap.log  ; MxE Vendor Window Capture
        ChkAdditionalCap    := 0
        AddX1               := 800
        AddY1               := 400
        AddX2               := 1200
        AddY2               := 600
        CapHotkey           := "~SC010" ; Qキー(透過)
        AdjustX             := 900
        Append_HTML         := 1
        Append_BaseDir      := Eソレス-00
        ChkDebug            := 0
        MoE_UserdataDir     =
        Chk_Excel           := 0
        Excel_Filename      =
        Chk_GoogleSpr       := 0
        GoogleSpr_User      =
        GoogleSpr_Pass      =
        GoogleSpr_SheetName =
        Chk_GoogleGAE       := 0
    }

    if (MoE_UserdataDir == "ERROR") {
        MoE_UserdataDir =
    }
    if (Excel_Filename == "ERROR") {
        Excel_Filename =
    }
    if (GoogleSpr_SheetName == "ERROR") {
        GoogleSpr_SheetName =
    }
    if (Chk_GoogleSpr ==  "ERROR") {
        Chk_GoogleSpr := 0
    }
    if (Chk_GoogleGAE ==  "ERROR") {
        Chk_GoogleGAE := 0
    }
    if (GoogleSpr_User == "ERROR") {
        GoogleSpr_User =
        GoogleSpr_Pass =
    } else if (GoogleSpr_User) {
        GoogleSpr_User := Crypt.Encrypt.StrDecrypt(GoogleSpr_User, str_magic, 5, 1) ;  decrypts the string using previously generated hash,AES_128 and MD5
        GoogleSpr_Pass := Crypt.Encrypt.StrDecrypt(GoogleSpr_Pass, str_magic, 5, 1) ;  decrypts the string using previously generated hash,AES_128 and MD5
    }
    ; 設定ダイアログ初期化
    Gui, CfgDlg:Add, Tab2, x2 h500 w400 vseltab, キャプチャ1|キャプチャ2|オプション

    Gui, CfgDlg:Tab, 1
    Gui, CfgDlg:Add, Button, x12 y450 w70 h30 gBtnOK Default, &OK

    Gui, CfgDlg:Add, CheckBox, x12  y40  w220 h20 vChkJpg, 指定領域をキャプチャ・&Jpg保存する
    Gui, CfgDlg:Add, Button,  x270  y40   w70 h30 gBtnSetOCRCapCoord, 範囲指定
    Gui, CfgDlg:Add, Text,     x12  y70   w90 h20 , 始点
    Gui, CfgDlg:Add, Text,     x22  y90   w60 h20 , X座標
    Gui, CfgDlg:Add, Text,     x22  y120  w60 h20 , Y座標
    Gui, CfgDlg:Add, Edit,     x72  y90   w40 h20 vx1, 
    Gui, CfgDlg:Add, Edit,     x72  y120  w40 h20 vy1, 
    Gui, CfgDlg:Add, Text,     x120 y70   w90 h20 , 終点
    Gui, CfgDlg:Add, Text,     x140 y90   w60 h20 , X座標
    Gui, CfgDlg:Add, Text,     x140 y120  w60 h20 , Y座標
    Gui, CfgDlg:Add, Edit,     x190 y90   w40 h20 vx2, 
    Gui, CfgDlg:Add, Edit,     x190 y120  w40 h20 vy2, 

    Gui, CfgDlg:Add, CheckBox, x12 y140 w220 h20 gChkOCR_Handler vChkOCR, 指定領域をキャプチャ・O&CR変換する
    ds1 := ChkOCR == 1 ? " " : "Disabled"
    ds2 := ChkAppend_OneText ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox, x22 y160 w220 h20 %ds1% gChkAppendTT_Handler vChkAppend_OneText hwndHChkAppend_OneText, 結果をひとつのテキストに追記する(&A)
    Gui, CfgDlg:Add, Text,     x32 y180 w140 h20 %ds1% %ds2% hwndHStaticTT, テキストファイル名(&T):
    Gui, CfgDlg:Add, Edit,    x160 y180 w140 h20 %ds1% %ds2% hwndHEditTT vTxtAppend_Filename,

    ds4 := Append_HTML ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox,  x12 y210 w100 h17 gChkAppend_HTML_Handler vAppend_HTML, HT&ML出力する
    Gui, CfgDlg:Add, Text,      x32 y230 w100 h20 %ds4% hwndHBasedir1 , ベースディレクトリ(&B) :
    Gui, CfgDlg:Add, Edit,     x160 y230 w140 h20 %ds4% hwndHBasedir2 vAppend_BaseDir, 
   ;Gui, CfgDlg:Add, Button,   x300 y245  w70 h20 %ds4% gBtnBaseDir, 参照

    ds5 := (Chk_Excel == 1 && ChkOCR) ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox,  x12 y260 w100 h17 %ds1% gChk_Excel_Handler vChk_Excel hwndHExcel1, E&xcel出力する
    Gui, CfgDlg:Add, Text,      x32 y280 w100 h20 %ds5% hwndHExcel2 , ファイル名(&F) :
    Gui, CfgDlg:Add, Edit,     x160 y275 w140 h20 %ds5% hwndHExcel3 vExcel_Filename, 
    Gui, CfgDlg:Add, Button,   x300 y275  w50 h20 gBtnSelectExcel, 参照

    ds6 := (Chk_GoogleSpr && ChkOCR) ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox,  x12 y300 w200 h17 %ds1% gChk_GoogleSpr_Handler vChk_GoogleSpr hwndHGoogle0, &Google SpreadSheetにアップする
    Gui, CfgDlg:Add, Text,      x32 y330 w140 h20 %ds6% hwndHGoogle1 , Google アカウント名(&A) :
    Gui, CfgDlg:Add, Edit,     x160 y325 w140 h20 %ds6% hwndHGoogle2 vGoogleSpr_User,
    Gui, CfgDlg:Add, Text,      x32 y360 w100 h20 %ds6% hwndHGoogle3 , パスワード(&P) :
    Gui, CfgDlg:Add, Edit,     x160 y355 w140 h20 %ds6% hwndHGoogle4 Password vGoogleSpr_Pass,
    Gui, CfgDlg:Add, Text,      x32 y390 w100 h20 %ds6% hwndHGoogle5 , シート名(&S) :
    Gui, CfgDlg:Add, Edit,     x160 y385 w140 h20 %ds6% hwndHGoogle6 vGoogleSpr_SheetName, 

    Gui, CfgDlg:Add, CheckBox,  x12 y410 w180 h17 %ds1% gChk_GoogleGAE_Handler vChk_GoogleGAE hwndHGoogleGAE0, Google App E&ngineにアップする
    Gui, CfgDlg:Add, Button,   x300 y410 w50 h20 gBtnGAE, 開く(&E)

    Gui, CfgDlg:Add, Button,   x100 y450 w70 h30 gBtnCancel, Cance&l

    Gui, CfgDlg:Tab, 2
    Gui, CfgDlg:Add, Button, x12 y450 w70 h30 gBtnOK Default, &OK
    ds3 := ChkAdditionalCap ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox, x12  y40   gChkAdditionalCap_Handler vChkAdditionalCap hwndHChkAdditionalCap, 同時に他の領域も撮影する(&2)
    Gui, CfgDlg:Add, Button,   x270 y40  w70  h30 %ds3% hwndHCoord1  gBtnSetAdditionalCapCoord, 範囲指定
    Gui, CfgDlg:Add, Text,     x12  y70  w90  h20 %ds3% hwndHCoord2  , 始点
    Gui, CfgDlg:Add, Text,     x22  y90  w60  h20 %ds3% hwndHCoord3  , X座標
    Gui, CfgDlg:Add, Text,     x22  y120 w60  h20 %ds3% hwndHCoord4  , Y座標
    Gui, CfgDlg:Add, Edit,     x72  y90  w40  h20 %ds3% hwndHCoord5  vAddX1, 
    Gui, CfgDlg:Add, Edit,     x72  y120 w40  h20 %ds3% hwndHCoord6  vAddY1, 
    Gui, CfgDlg:Add, Text,     x120 y70  w90  h20 %ds3% hwndHCoord7  , 終点
    Gui, CfgDlg:Add, Text,     x140 y90  w60  h20 %ds3% hwndHCoord8  , X座標
    Gui, CfgDlg:Add, Text,     x140 y120 w60  h20 %ds3% hwndHCoord9  , Y座標
    Gui, CfgDlg:Add, Edit,     x190 y90  w40  h20 %ds3% hwndHCoord10 vAddX2, 
    Gui, CfgDlg:Add, Edit,     x190 y120 w40  h20 %ds3% hwndHCoord11 vAddY2, 
    Gui, CfgDlg:Add, Text,     x12  y150, (OCRは行いません)

    Gui, CfgDlg:Add, Button,   x100 y450 w70 h30 gBtnCancel, Cance&l

    Gui, CfgDlg:Tab, 3
    Gui, CfgDlg:Add, Button, x12 y450 w70 h30 gBtnOK Default, &OK
    Gui, CfgDlg:Add, Text,      x12 y40 w150 h20 , MoEのuserdataディレクトリ(&U) :
    Gui, CfgDlg:Add, Edit,      x32 y60 w240 h20 vMoE_UserdataDir, 
    Gui, CfgDlg:Add, Button,   x280 y60  w50 h20 gBtnMoEDir, 参照

    Gui, CfgDlg:Add, Text,      x12  y90 w120 h20 , キャプチャホットキー(&H) :
    Gui, CfgDlg:Add, Edit,      x32 y110 w140 h20 vCapHotkey,

    Gui, CfgDlg:Add, Button,    x12 y140 w200 h20 gOmakeAdjustX, ウィンドウのX座標位置合わせ(&W),
    Gui, CfgDlg:Add, Edit,     x220 y140 w50 h20 vAdjustX,

    Gui, CfgDlg:Add, CheckBox,  x12 y170 w100 h20 vChkDebug, デバッグ(&D)
    Gui, CfgDlg:Add, Button,   x100 y450 w70 h30 gBtnCancel, Cance&l

    ; タスクトレイメニューの初期化
    Menu, Tray, Add ; Add Separator.
    Menu, Tray, Add, 設定(&T), MenuSettingDlg
    Menu, Tray, Add, Status, MenuStatDlg
    Menu, Tray, Check, Status

    if (mvc_1st_run) {
        Gosub, MenuSettingDlg
    }
    ; ホットキーの有効化
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, On
    }

    if (Chk_GoogleSpr == 1 && GoogleSpr_Pass && GoogleSpr_User && GoogleSpr_SheetName) {
        if (PySockInit(GoogleSpr_User, GoogleSpr_Pass, GoogleSpr_SheetName) ) { ; 初回のみ
            MsgBox, Pythonソケット 初期化エラー!
        } else {
            py_init := True
        }
    }

    ; 状態ウィンドウ(ラベルが付けられない・・・)
    Gui StatDlg:Default
    Gui, StatDlg:Color, 0066cc
   ;Gui StatDlg:-Caption
    Gui, StatDlg:Add, CheckBox, x5   y150 w120 h20 vAlwaysOnTop gAlwaysOnTop_Handler, 常に手前に表示(&A)
    Gui, StatDlg:Add, ListView, x0   y0   w150 h150 Grid vlvwtask1, ID  |Capture task
    Gui, StatDlg:Add, ListView, x150 y0   w240 h150 Grid vlvwtask2, ID  |OCR task
    ; Generated using SmartGUI Creator 4.0
    stat_pos := "x0 y570 h170 w391"
    Gui, StatDlg:Show, NoActivate %stat_pos%, Status
    stat_active := 1
    Gui, StatDlg:Color, eeeeee

#include Capture2Text_BackEnd.ahk
return

GuiClose:
    Gui, StatDlg:Hide
    stat_active := false
return

GuiApplyValue() {
    Global

    GuiControl, CfgDlg:, x1, %x1%
    GuiControl, CfgDlg:, y1, %y1%
    GuiControl, CfgDlg:, x2, %x2%
    GuiControl, CfgDlg:, y2, %y2%

    GuiControl, CfgDlg:, ChkJpg, %ChkJpg%
    GuiControl, CfgDlg:, ChkOCR, %ChkOCR%
    GuiControl, CfgDlg:, ChkAppend_OneText, %ChkAppend_OneText%
    GuiControl, CfgDlg:, TxtAppend_Filename, %TxtAppend_Filename%

    GuiControl, CfgDlg:, ChkAdditionalCap, %ChkAdditionalCap%
    GuiControl, CfgDlg:, addx1, %addx1%
    GuiControl, CfgDlg:, addy1, %addy1%
    GuiControl, CfgDlg:, addx2, %addx2%
    GuiControl, CfgDlg:, addy2, %addy2%

    GuiControl, CfgDlg:, CapHotkey, %CapHotkey%
    GuiControl, CfgDlg:, AdjustX, %AdjustX%

    GuiControl, CfgDlg:, Append_HTML, %Append_HTML%
    GuiControl, CfgDlg:, Append_BaseDir, %Append_BaseDir%
    GuiControl, CfgDlg:, ChkDebug, %ChkDebug%
    GuiControl, CfgDlg:, MoE_UserdataDir, %MoE_UserdataDir%

    GuiControl, CfgDlg:, Chk_Excel, %Chk_Excel%
    GuiControl, CfgDlg:, Excel_Filename, %Excel_Filename%

    GuiControl, CfgDlg:, Chk_GoogleSpr, %Chk_GoogleSpr%
    GuiControl, CfgDlg:, GoogleSpr_User, %GoogleSpr_User%
    GuiControl, CfgDlg:, GoogleSpr_Pass, %GoogleSpr_Pass%
    GuiControl, CfgDlg:, GoogleSpr_SheetName, %GoogleSpr_SheetName%

    GuiControl, CfgDlg:, Chk_GoogleGAE, %Chk_GoogleGAE%
    return
}

WriteCfg2INI() {
    Global
    IniWrite, %x1%,                    %mvinifile%, Coord, x1
    IniWrite, %y1%,                    %mvinifile%, Coord, y1
    IniWrite, %x2%,                    %mvinifile%, Coord, x2
    IniWrite, %y2%,                    %mvinifile%, Coord, y2
    IniWrite, %ChkJpg%,                %mvinifile%, Coord, ChkJpg
    IniWrite, %ChkOCR%,                %mvinifile%, Coord, ChkOCR
    IniWrite, %ChkAppend_OneText%,     %mvinifile%, Coord, ChkAppend_OneText
    IniWrite, %TxtAppend_Filename%,    %mvinifile%, Coord, TxtAppend_Filename
    IniWrite, %ChkAdditionalCap%,      %mvinifile%, Coord, ChkAdditionalCap
    IniWrite, %AddX1%,                 %mvinifile%, Coord, AddX1
    IniWrite, %AddY1%,                 %mvinifile%, Coord, AddY1
    IniWrite, %AddX2%,                 %mvinifile%, Coord, AddX2
    IniWrite, %AddY2%,                 %mvinifile%, Coord, AddY2
    IniWrite, %CapHotkey%,             %mvinifile%, Coord, CapHotkey
    IniWrite, %AdjustX%,               %mvinifile%, Coord, AdjustX

    IniWrite, %Append_HTML%,           %mvinifile%, Coord, Append_HTML
    IniWrite, %Append_BaseDir%,        %mvinifile%, Coord, Append_BaseDir
    IniWrite, %ChkDebug%,              %mvinifile%, Coord, ChkDebug
    IniWrite, %MoE_UserdataDir%,       %mvinifile%, Coord, MoE_UserdataDir

    IniWrite, %Chk_Excel%,             %mvinifile%, Coord, Chk_Excel
    IniWrite, %Excel_Filename%,        %mvinifile%, Coord, Excel_Filename

    IniWrite, %Chk_GoogleSpr%,         %mvinifile%, Coord, Chk_GoogleSpr

    ; Iniファイルを書くときに暗号化する
    hash := Crypt.Encrypt.StrEncrypt(GoogleSpr_User, str_magic, 5, 1) ; encrypts string using AES_128 encryption and MD5 hash
    IniWrite, %hash%,        %mvinifile%, Coord, GoogleSpr_User
    hash := Crypt.Encrypt.StrEncrypt(GoogleSpr_Pass, str_magic, 5, 1) ; encrypts string using AES_128 encryption and MD5 hash
    IniWrite, %hash%,        %mvinifile%, Coord, GoogleSpr_Pass

    IniWrite, %GoogleSpr_SheetName%,   %mvinifile%, Coord, GoogleSpr_SheetName

    IniWrite, %Chk_GoogleGAE%,         %mvinifile%, Coord, Chk_GoogleGAE
}

Update_Task1(ID, caption) {
    Global lvwtask1
    Gui StatDlg:Default
    Gui, ListView, lvwtask1
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        dout(lvres)
        if (lvres == ID ) {
            LV_Modify(A_Index, "", ID, caption)
            return
        }
    }
    LV_Insert(1, "", ID, caption)
}

Update_Task2(ID, caption) {
    Global lvwtask2
    Gui StatDlg:Default
    Gui, ListView, lvwtask2
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        dout(lvres)
        if (lvres == ID ) {
            LV_Modify(A_Index, "", ID, caption)
            return
        }
    }
    LV_Insert(1, "", ID, caption)
}

Delete_Task(ID) {
    Global lvwtask1, lvwtask2

    Gui StatDlg:Default
    Gui, ListView, lvwtask1
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        dout(lvres)
        if (lvres == ID ) {
            LV_Delete(A_Index)
        }
    }
    Gui, ListView, lvwtask2
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        dout(lvres)
        if (lvres == ID ) {
            LV_Delete(A_Index)
        }
    }
}

AlwaysOnTop_Handler:
    GuiControlGet, AlwaysOnTop, , AlwaysOnTop
    if (AlwaysOnTop) {
        Gui StatDlg:+AlwaysOnTop
        WinSet, Transparent, 150
    } else {
        Gui StatDlg:-AlwaysOnTop
        WinSet, Transparent, 255
    }
return

class capjob {

    __New(count, log_fname) {
        this.mvc_log_fname := log_fname
        this.ID := count
        this.bmp_fname := "Output\mvc" . this.ID . ".bmp"
       ;this.bmp_fname2 := "Output/mvc" . this.ID . "-mono.bmp"
        this.CMPL := 0
        this.bmpCMPL := false
        FileDelete, % this.bmp_fname
        return this
    }

    captureBMP() {
        Global x1, y1, x2, y2, ChkDebug

        Update_Task1(this.ID, "BMP撮影開始")
        dout("BMP [" this.ID "] Start")
        dout("Filename:  " . this.bmp_fname)
        ; 撮影
        captureRect = % x1 ", " y1 ", " x2 ", " y2    ; Form the screen capture rectangle
        dout(A_ThisFunc ": " captureRect " into " this.bmp_fname)
        CaptureScreen(captureRect, 0, this.bmp_fname)

        dout("BMP [" this.ID "] End")
        this.bmpCMPL := true

        if (ChkDebug) {
            ToolTip, % "ジョブ " this.ID " 撮影完了。"
            SetTimer, ttoff, -1000
        }
    }

    OCR() {
        Global ChkDebug, MONO_FILTER
        if(!this.bmpCMPL) {
            Update_Task2(this.ID, "BMP待ち(1)")
            dout("OCR [" this.ID "] BMP待ち(1)")
            return
        }
        ; 開始時間
        Update_Task2(this.ID, "OCR開始")
        if(ChkDebug){
            ToolTip, % "ジョブ " this.ID " OCRを開始します。"
            SetTimer, ttoff, -1000
        }
        this.startTime := A_TickCount

        ; 白黒減色化・反転する(インストールされている場合のみ。)
        if (FileExist(MONO_FILTER)) {
            Update_Task2(this.ID, "反転処理開始")
            cmdline := % MONO_FILTER " /160  " this.bmp_fname " /O /R"
            dout("monorize: " . cmdline . "-->" . this.bmp_fname " Error:" ErrorLevel)
            RunWait, %cmdline%, , Hide
            Update_Task2(this.ID, "反転処理終了")
        }

        dout("OCR [" this.ID "] Start: " this.bmp_fname "  ==>  " this.mvc_log_fname)
        doOCR(this.bmp_fname, this.mvc_log_fname)
        dout("OCR [" this.ID "] End")
        if (ChkDebug) {
            ToolTip, % "ジョブ " this.ID " OCR完了しました。"
            SetTimer, ttoff, -1000
        }

        ; 結果をバッファに保存する
        FileRead, buffer, % this.mvc_log_fname
        this.out_buffer := buffer
        this.CMPL := 1

        ; 終了時間を記録する
        this.elapsedTime := A_TickCount - this.startTime
        Update_Task2(this.ID, "OCR完了 " this.elapsedTime " [msec]")
    }

    captureJpg() {
        Global x1, y1, x2, y2, Append_BaseDir

        Update_Task1(this.ID, "Jpg撮影1")
        captureRect = % x1 ", " y1 ", " x2 ", " y2    ; Form the screen capture rectangle

        fbuf = % "mvc-" this.out_file_key "-ocr.jpg"
        this.out_file_jpg1 := fbuf

        fpath = fbuf
        if(Append_BaseDir) {
            FileCreateDir, %Append_BaseDir%
            fpath = %Append_BaseDir%\%fbuf%
        }

        CaptureScreen(captureRect, false, fpath, 30)
        return
    }

    captureAdditionalJpg() {
        Global addx1, addy1, addx2, addy2, Append_BaseDir

        Update_Task1(this.ID, "Jpg撮影2")
        captureRect = % addx1 ", " addy1 ", " addx2 ", " addy2

        ; ベースファイル名
        fbuf = % "mvc-" this.out_file_key "-map.jpg"
        this.out_file_jpg2 := fbuf

        ; 相対パス
        fpath = fbuf
        if(Append_BaseDir) {
            FileCreateDir, %Append_BaseDir%
            fpath = %Append_BaseDir%\%fbuf%
        }
        CaptureScreen(captureRect, false, fpath, 30)
        return
    }

    __Delete() {
        FileDelete, % this.bmp_fname
        dout("OCR [" this.ID "] Destructor")
        Delete_Task(this.ID)
    }
}

ExitSub:
    if (py_init) {
        SendData(MainSocket, "py_exit")
        NormalClose()
    }
    ExitApp
return

MenuSettingDlg:
    ; Generated using SmartGUI Creator 4.0
    ; ホットキーの無効化
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, Off
    }
    Gui, CfgDlg:Show, , mvc:家ベンダ用スクショ・OCR
    GuiApplyValue()
Return

MenuStatDlg:
    Menu, Tray, ToggleCheck, Status
    if (stat_active) {
        Gui, StatDlg:Hide
        dout("stat hide")
        stat_active := false
    } else {
        Gui, StatDlg:Show, x0 %stat_pos%, Status
        dout("stat show")
        stat_active := true
    }
return

BtnMoEDir:
    FileSelectFolder, tmpMoE_UserdataDir, , , MoEのシステムログを検出するディレクトリを指定してください。
    if (tmpMoE_UserdataDir) {
        MoE_UserdataDir := tmpMoE_UserdataDir
        GuiControl, CfgDlg:, MoE_UserdataDir, %MoE_UserdataDir%
    }
return

BtnBaseDir:
    FileSelectFolder, tmpAppend_BaseDir, , 1+2+4, ファイル(大量に出ます)の出力先ディレクトリを指定してください。
    if (tmpAppend_BaseDir) {
        Append_BaseDir := tmpAppend_BaseDir
        GuiControl, CfgDlg:, Append_BaseDir, %Append_BaseDir%
    }
return

BtnSelectExcel:
    FileSelectFile, tmpExcelPath, , , 出力先エクセルファイル(既存)を指定してください。
    if (tmpExcelPath) {
        Excel_Filename := tmpExcelPath
        GuiControl, CfgDlg:, Excel_Filename, %Excel_Filename%
    }
return

BtnOK:
    Gui, CfgDlg:Submit
    Gui, CfgDlg:Hide
    WriteCfg2INI()
    ToolTip, リロードします ; ホットケー再設定がめどい
    Sleep, 500
    Reload
return

BtnGAE:
    Run, %ComSpec% /c start %cloud_url%,, Hide
return

#IfWinActive, ahk_class AutoHotkeyGUI
Esc::
#IfWinActive
BtnCancel:
    ; ホットキーの有効化
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, On
    }
    Gui, CfgDlg:Hide
return

; 領域設定1
BtnSetOCRCapCoord:
    last_coord_set := 1
    SetCoord()
return

; 領域設定2
BtnSetAdditionalCapCoord:
    last_coord_set := 2
    SetCoord()
return

ChkOCR_Handler:
    GuiControlGet, stat, , ChkOCR
    if (stat) {
        GuiControl, Enable, %HChkAppend_OneText%
    } else {
        GuiControl, Disable, %HChkAppend_OneText%
    }
    Gosub, ChkAppendTT_Handler
    Gosub, Chk_Excel_Handler
    GoSub, Chk_GoogleSpr_Handler
    GoSub, Chk_GoogleGAE_Handler
return

; ChkAppend_OneText, 結果をひとつのテキストに追記する(&A)
ChkAppendTT_Handler:
    GuiControlGet, stat1, , ChkOCR
    GuiControlGet, stat2, , ChkAppend_OneText
    if (stat1 && stat2) {
        GuiControl, Enable, %HStaticTT%
        GuiControl, Enable, %HEditTT%
    } else {
        GuiControl, Disable, %HStaticTT%
        GuiControl, Disable, %HEditTT%
    }
return

ChkAdditionalCap_Handler:
    GuiControlGet, stat, , ChkAdditionalCap
    Loop, 11
    {
        chwnd_name = HCoord%A_Index%
        chwnd := %chwnd_name%
        if (stat) {
            GuiControl, Enable, %chwnd%
        } else {
            GuiControl, Disable, %chwnd%
        }
;       OutputDebug % "chwnd: " chwnd " stat:" stat ErrorLevel
    }
return

ChkAppend_HTML_Handler:
    GuiControlGet, stat, , Append_HTML
    if (stat) {
        GuiControl, Enable,  %HBasedir1%
        GuiControl, Enable,  %HBasedir2%
    } else {
        GuiControl, Disable, %HBasedir1%
        GuiControl, Disable, %HBasedir2%
    }
return

Chk_Excel_Handler:
    GuiControlGet, stat1, , ChkOCR
    if (stat1) {
        GuiControl, Enable,  %HExcel1%
    } else {
        GuiControl, Disable,  %HExcel1%
    }

    GuiControlGet, stat2, , Chk_Excel
    if (stat1 && stat2) {
        GuiControl, Enable,  %HExcel2%
        GuiControl, Enable,  %HExcel3%
    } else {
        GuiControl, Disable, %HExcel2%
        GuiControl, Disable, %HExcel3%
    }
return

Chk_GoogleSpr_Handler:
    GuiControlGet, stat1, , ChkOCR
    if (stat1) {
        GuiControl, Enable,  %HGoogle0%
    } else {
        GuiControl, Disable,  %HGoogle0%
    }

    outputdebug % Chk_GoogleSpr
    GuiControlGet, stat2, , Chk_GoogleSpr
    if (stat1 && stat2) {
        Loop, 6
        {
            hwndGoog = HGoogle%A_Index%
            GuiControl, Enable, %hwndGoog%
        }
    } else {
        Loop, 6
        {
            hwndGoog = HGoogle%A_Index%
            GuiControl, Disable, %hwndGoog%
        }
;Chk_GoogleSpr_Handler2("Disable")
    }
return

Chk_GoogleSpr_Handler2(stat3) {
    Global
    Local hwndGoog

    Loop, 6
    {
        hwndGoog = HGoogle%A_Index%
        GuiControl, %stat3%, %hwndGoog%
        outputdebug % stat3 " " hwndGoog
    }
    return
}

Chk_GoogleGAE_Handler:
return

; 指定座標をキャプチャしてOCR + jpg保存する。
do_capture:
    _do_capture()
return

_do_capture() {
    Global job_count, mvc_log_fname, AryJob, TxtAppend_Filename, Append_BaseDir, ChkOCR, ChkJpg, ChkAdditionalCap, ChkDebug, mvc_log_one_fname

    snd_path = %A_ScriptDir%\shatter.wav
    if (FileExist(snd_path)) {
        SoundPlay, snd_path
    } else {
        SoundBeep, 800, 200
    }

    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, Off
    }
    SetTimer, ScheduledOCR, Off
    dout("Triggered" job_count "!")

    out_file_key = % A_YYYY "-" A_MM "-" A_DD "_" A_Hour A_Min A_Sec "-" job_count  ; ファイル名に付与する日付
    out_text_key = % A_YYYY "/" A_MM "/" A_DD " " A_Hour ":" A_Min ":" A_Sec  ; テキスト内に付与する区切りの日付時刻
    out_text_date = % A_YYYY "/" A_MM "/" A_DD  ; テキスト内に付与する区切りの日付

    cjob := new capjob(job_count++, mvc_log_fname)

    Update_Task1(cjob.ID, "撮影中・・・")

    ; パスを決める
    html_fname = mvc.html
    mvc_log_fname = mvc-%out_file_key%.txt
    mvc_log_one_fname = %TxtAppend_Filename%
    if(Append_BaseDir) {
        FileCreateDir, %Append_BaseDir%
        html_fname          = % Append_BaseDir . "\" . html_fname
        mvc_log_fname       = % Append_BaseDir . "\" . mvc_log_fname
    }

    cjob.out_file_key       := out_file_key
    cjob.out_text_key       := out_text_key
    cjob.out_text_date      := out_text_date
    cjob.html_fname         := html_fname
    cjob.mvc_log_fname      := mvc_log_fname
    cjob.mvc_log_one_fname  := mvc_log_one_fname

    if (ChkOCR) {
        bmpstart := A_TickCount
        cjob.captureBMP()              ; 先に撮影を済ませる
    }
    if (ChkJpg) {
        cjob.captureJpg()                ; jpgの保存
    }
    if (ChkAdditionalCap) {
        cjob.captureAdditionalJpg()      ; 追加領域の保存
    }

    AryJob.Insert(cjob)         ; ジョブの登録
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, On
        dout("ホットキーを有効化しました")
    }

    SetTimer, ScheduledOCR, 200 ; 別スレッドでOCR変換を実行
    SetTimer, ttoff, -1000
    Update_Task1(cjob.ID, "撮影完了")

    return
}

dout(val) {
    Global ChkDebug
    if (ChkDebug) {
        OutputDebug % val
    }
}

ScheduledOCR:
    if (!AryJob.MaxIndex()) {
        SetTimer, ScheduledOCR, Off
        return  ; 全部処理が終わったらタイマ削除
    }
    for idx, jj in AryJob {
        if (jj.CMPL == 0) {
            if (ChkOCR) {
                jj.OCR()
            } else {
                jj.CMPL := 1 ; 何もしない
            }
        } else if (jj.CMPL == 1) {
            ; 終了処理
            captureFinished(jj)
            jj.CMPL := 2
        } else if (jj.CMPL == 2) {
            AryJob.Remove(idx)
        }
        break
    }
return

; OCR終了処理
captureFinished(job) {
    Global
    Local jbuf2, svr, area, xc, zc, alter,address, iServer, iAlter, iArea, snd_path

    file_st_time := A_TickCount

    ; 設定が有効ならば、MoEのシステムログから得たエリア情報と座標を連結する。
    svr=
    area=
    xc=
    zc=
    alter = 
    address =
    if (ChkOCR && MoE_UserdataDir) {
        GetMoeCoord(svr, area, xc, zc)
        ; エリア情報がとれている場合、座標から家の番地を取得する
        if (area) {
            resa := GetMoeAddress(area, xc, zc)
            StringSplit, alter_addr, resa, "_"
            alter = %alter_addr1%
            address = %alter_addr2%
            ;outputdebug % resa "," alter "," address
        }
    }

    ; 製作者名をマスクする
    if (ChkOCR) {
        jbuf := job.out_buffer
        jbuf2=
        Loop, Parse, jbuf, `n
        {
            buf := Delete_Weapon_Creator(A_LoopField)
            if (strlen(buf) < 3) {
                continue
            }
            jbuf2 .= buf . "`n"
        }
        job.out_buffer := jbuf2
    }

    ; 設定が有効ならば、一つのhtmlに追記する。
    if (Append_HTML) {
        Update_Task2(job.ID, "HTML出力中")
        FileGetSize, hsize, % job.html_fname
        if (ErrorLevel) {
            FileAppend, <table>, % job.html_fname
        }
        hbuf1 := "<tr><td rowspan=4><img src=" job.out_file_jpg1 "></td></tr>`n"
        hbuf1 .= "<tr><td>          <img src=" job.out_file_jpg2 "></td></tr>`n"
        hbuf1 .= "<tr><td><pre>" job.out_text_date "</pre>         </td></tr>`n"
        hbuf2 := job.out_buffer
        hbuf2 := RegExReplace(hbuf2, ">", "&gt")
        hbuf2 := RegExReplace(hbuf2, "<", "&lt")
        hbuf1 .= "<tr><td><pre><B>" svr "<BR>" area "<BR>最寄り:" alter "<BR>" address "<BR>" xc "," zc "</B>`n" hbuf2 "</pre>            </td></tr>`n"
        FileAppend, %hbuf1%, % job.html_fname
    }

    ; 一つのテキストファイルに書き出す。
    ; システムログを取得済みの場合、頭にタブ区切りで付与する。
    job.csvfname := "spr_tmp_" job.ID ".csv"
    FileDelete, % job.csvfname
    if (ChkOCR) {
        Update_Task2(job.ID, "テキスト出力中")
        jbuf := job.out_buffer
        Loop, Parse, jbuf, `n
        {
            if (strlen(A_LoopField) < 3) {
                continue
            }

            ; 品名と価格を分割
            parse_price_item(A_LoopField, price, item)

            ; タブ区切りのテキストファイル
            wbuf := % job.out_text_date "`t" svr "`t" area "`t" alter "`t" address "`t" xc "`t" zc "`t" price "`t" item "`n"
            if (ChkAppend_OneText && TxtAppend_Filename) {
                FileAppend, % wbuf, % mvc_log_one_fname
            }

            ; Google SpreadSheetへアップするデータに蓄積する
            dd := job.out_text_date
            wbuf = %dd%`t%svr%`t%area%`t%alter%`t%address%`t%xc%`t%zc%`t%price%`t%item% `n
            if (Chk_GoogleSpr == 1 && GoogleSpr_Pass && GoogleSpr_User && GoogleSpr_SheetName) {
                FileAppend, % wbuf, % job.csvfname
            }
        }
    }

    ; Excel出力
    if (ChkOCR && Chk_Excel == 1 && Excel_Filename) {
        Update_Task2(job.ID, "Excel出力中")
        Append_Excel(job.out_text_date, svr, area, alter, address, xc, zc, job.out_buffer)
    }

    if (Chk_GoogleSpr == 1 && GoogleSpr_Pass && GoogleSpr_User && GoogleSpr_SheetName) {
        Update_Task2(job.ID, "スプレッドシート出力中")
        IfExist, % job.csvfname
        {
            if (!PySockInit(GoogleSpr_User, GoogleSpr_Pass, GoogleSpr_SheetName) ) { ; 初回のみ
                ; Google SpreadSheetへアップ
                ToolTip, Google SpreadSheetへアップ中・・・
                SetTimer, ttoff, Off

                SendData(MainSocket, "insert " job.csvfname "|")

                ToolTip, 終了.
                ToolTip
            }
        }
    }

    if (Chk_GoogleGAE && ChkOCR) {
        Update_Task2(job.ID, "GAE出力中")
        ; クラウドにアップする
        gbuffer =
        jbuf := job.out_buffer
        Loop, Parse, jbuf, `n
        {
            if (strlen(A_LoopField) < 3) {
                continue
            }

            ; 品名と価格を分割
            parse_price_item(A_LoopField, price, item)
            gbuffer .= price "`t" item "`n"
            dout (gbuffer)
        }
        iServer := server_to_int(svr)
        iArea   := area_to_int(area)
        iAlter  := alter_to_int(iArea, alter)
        post_to_gae(iServer, iArea, iAlter, address, xc, zc, gbuffer )
    }

    file_elapsed := A_TickCount - file_st_time
    Update_Task2(job.ID, "処理完了 OCR: " job.elapsedTime "[msec] 他: " file_elapsed "[msec]")
    if (ChkDebug) {
        ToolTip, % "処理完了 ジョブ:" job.ID "`n    OCR処理時間:" job.elapsedTime " [msec]`n    ファイル処理時間:" file_elapsed " [msec]`n"
        SetTimer, ttoff, -1000
    }

    snd_path = %A_ScriptDir%\ocrfinish.wav
    if (FileExist(snd_path)) {
        SoundPlay, snd_path
    } else {
        SoundBeep, 600, 200
    }
    return
}

; Preset the rect of capture area
SetCoord() {
    Global

    MsgBox, キャプチャ範囲を設定します。`n開始位置をクリックして灰色の四角形が出た後、`nマウスを右下の終了位置方向へ向かって移動させ、`n終了位置で再度 クリックしてください。`n(キャンセルする場合は右クリックしてください)
    startCaptureMode1()
    return
}

#If (captureMode)
~LButton::
    if (captureMode == 1) {
        startCaptureMode2()
    } else {
        ; End capture mode
        endCaptureMode()

        applyCoord()
    }
return

ESC::
~RButton::
    ; Update the active capture point
    updateActiveCoordWithMousePos()

    ; End capture mode
    endCaptureMode()
    msgbox, 範囲指定をキャンセルしました。
return
#If

; Start capture mode
startCaptureMode1() {
    global
    Gui, Capture:Destroy

    ; Set the capture mode flag
    captureMode = 1

    ; Set the active capture corner to the bottom-right corner
    topLeftCoordActive = 0
}

startCaptureMode2() {
    global

    captureMode = 2

    ; Initialize the capture box coordinates
    MouseGetPos, cx1, cy1
    MouseGetPos, cx2, cy2

    ; Create a timer to update the capture box
    SetTimer, UpdateCaptureBox, %BOX_UPDATE_RATE%

    ; Make the first update immediate rather than waiting for the timer
    Gosub, UpdateCaptureBox
}

; Update the position of the capture box.
UpdateCaptureBox:
  ; Set the box color
  captureBoxColor := 0080FF
  Gui, Capture:Color, %captureBoxColor%

  ; Make the GUI window the last found window for use by the line below
  ; Also keep the window on top of other windows and don't show in the task bar
  Gui, Capture:+LastFound +AlwaysOnTop -Caption +ToolWindow

  ; Set the box opacity
  CaptureBoxAlpha=40
  captureBoxAlphaScaled := Round((captureBoxAlpha / 100.0) * 255)
  WinSet, Transparent, %captureBoxAlphaScaled%

  ; Update the active capture point
  updateActiveCoordWithMousePos()

  ; Bound the capture box coordinates
  if(topLeftCoordActive) {
    if(cx1 + 1 > cx2)
      cx1 := cx2 - 1

    if(cy1 + 1 > cy2)
      cy1 := cy2 - 1
  } else {
    if(cx2 - 1 < cx1)
      cx2 := cx1 + 1

    if(cy2 - 1 < cy1)
      cy2 := cy1 + 1
  }

  ; Display the capture box
  Gui, Capture:Show, % "X" cx1 " Y" cy1 " W" cx2-cx1 " H" cy2-cy1

  ; Handle the case where the capture ended but the timer still had one update left
  if(captureMode == 0) {
    Gui, Capture:Destroy
    return
  }

return

; Update the active capture coordinates with the current mouse position
updateActiveCoordWithMousePos() {
  MouseGetPos, x, y

  setActiveCaptureCoords(x, y)

} ; updateActiveCoordWithMousePos


; Set the active capture coordinates
setActiveCaptureCoords(x, y) {
    global

    if(topLeftCoordActive) {
        cx1 := x
        cy1 := y

        if(moveBothCorners) {
            cx2 := cx1 + bothCornersWidth
            cy2 := cy1 + bothCornersHeight
        }
    } else {
        cx2 := x
        cy2 := y

        if(moveBothCorners) {
            cx1 := cx2 - bothCornersWidth
            cy1 := cy2 - bothCornersHeight
        }
    }
}

; End COR capture mode
endCaptureMode() {
    global

    ; Clear the capture mode flag
    captureMode = 0

    ; Stop the timer that updates the capture box
    SetTimer, UpdateCaptureBox, Off

    ; Remove the capture box
    Gui, Capture:Destroy

    ; Update the active capture point
    updateActiveCoordWithMousePos()

}

applyCoord() {
    Global

    ; End capture mode

    ; 値を引っ張る
    if (last_coord_set == 1) {
        x1 := cx1
        y1 := cy1
        x2 := cx2
        y2 := cy2
    } else if (last_coord_set == 2) {
        addx1 := cx1
        addy1 := cy1
        addx2 := cx2
        addy2 := cy2
    }
    GuiApplyValue()

    ToolTip, % "座標を指定しました。`n  X:  " cx1 "," cy1 "`n  Y:  " cx2 "," cy2 "`n設定先:" last_coord_set
    SetTimer, ttoff, -3000
}

ttoff:
    ToolTip
return

OmakeAdjustX:
    MsgBox, , おまけ機能
        , ベンダウィンドウを{%AdjustX%,0}の位置へ移動します。`n左角にベンダウィンドウを寄せてください。`n(OK押してから3秒後に開始)

    ToolTip, 3
    Sleep, 1000
    ToolTip, 2
    Sleep, 1000
    ToolTip, 1
    Sleep, 1000
    ToolTip

    ; 掴む
    corner_x := 15
    Click, ,  %corner_x%, 11, , , D

    ; 離す
    mvx2 := AdjustX + corner_x
    Click, , %mvx2%, 11, , , U
return

GetMoESystemLog() {
    Global MoE_UserdataDir, ChkOCR
    static moe_syslog_fname
    if (moe_syslog_fname) {
        return moe_syslog_fname
    }
    if (!ChkOCR or !MoE_UserdataDir) {
        return
    }
    AryFilename := {}
    AryFileDate := {}
    ; Find file pattern
    pattern := % MoE_UserdataDir "\mlog_" SubStr(A_YYYY,3) "_" A_MM "_" A_DD "_0.txt"
   ;Outputdebug % pattern
    date_newest =
    date_newest_idx := 0
    Loop, %pattern%, 0, 1
    {
        AryFilename.Insert(A_LoopFileFullPath)
        FileGettime, buf, %A_LoopFileFullPath%, M
        if (buf > date_newest) {
            date_newest := buf
            date_newest_idx := A_Index
        }
       ;Outputdebug % A_LoopFileFullPath ":" buf
        AryFileDate.Insert(buf)
    }
    ;Outputdebug % "newest: " AryFilename[date_newest_idx] " : " AryFileDate[date_newest_idx]
    moe_syslog_fname := AryFilename[date_newest_idx]
    return moe_syslog_fname
}

GetMoeCoord(ByRef Server, ByRef Area, ByRef xCoord, ByRef zCoord) {
    fname := GetMoESystemLog()
    if (!fname) {
        return
    }

    if (InStr(fname, "\EMERALD_")) {
        Server = EMERALD
    }
    if (InStr(fname, "\DIAMOND_")) {
        Server = DIAMOND
    }
    if (InStr(fname, "\PEARL")) {
        Server = PEARL
    }

    newest_server =
    newest_coord =
    buf=
    FileEncoding , cp932    ; Sjisに設定
    Loop, Read, %fname%
    {
        ; 先頭20文字をカット
        if(InStr(A_LoopReadLine, "に入りました")) {
            newest_server := SubStr(A_LoopReadLine, 20)
        }
        if(InStr(A_LoopReadLine, "Server:")) {
            newest_server := SubStr(A_LoopReadLine, 20)
        }
        if(InStr(A_LoopReadLine, "X:")
            && InStr(A_LoopReadLine, "Y:")
            && InStr(A_LoopReadLine, "Z:") ) {
            newest_coord := SubStr(A_LoopReadLine, 20)
        }
/*
Sample             (-->20文字)
13/02/17 04:08:17: 城下町ビスク 中央エリア 地域 [Server:PEARL]
13/02/17 00:57:07: X:29.93 Y:1.06 Z:33.42
13/02/23 03:47:18: ソレス渓谷(Ancient Age) に入りました
1                  20                    42
*/

    }

    ; エリア情報を抽出する
    entpos := InStr(newest_server, "に入りました")
    if(entpos) {
        ; まだエリア情報がない(もしくは、取っていない) : エリアに入った情報だけ抜き出す。
        Area := SubStr(newest_server, 1, entpos-2)
;dout("newest_server: " newest_server " entpos: " entpos " area: " area)
    } else {
        pos := InStr(newest_server, "[")
        StringLeft, Area, newest_server, pos-5
    }

    ; 座標情報を抽出する
    if (newest_coord) {
        pos := InStr(newest_coord, "X:")
        xCoord := SubStr(newest_coord, pos+2)
        pos := InStr(xCoord, " ")
        StringLeft, xCoord, xCoord, pos-1

        pos := InStr(newest_coord, "Z:")
        zCoord := SubStr(newest_coord, pos+2)
    }

    ; サーバ・エリア情報と座標を連結する
    buf := % newest_server "," newest_coord

    FileEncoding , UTF-8
    return buf
}

; 現在位置の最寄りの家の番地を取得する
GetMoeAddress(area, xcoord, zcoord) {
    if (!area, !xcoord || !zcoord) {
        return
    }
    FileEncoding , cp932    ; Sjisに設定
    ary_addr := {}
    ; ファイル読み込み
    Loop, Read, moe_area.def
    {
      addr := {}
      Loop, Parse, A_LoopReadLine, `,
      {
        ;Outputdebug, % "Insert:" A_Index "," A_LoopField
        addr.Insert(A_Index, A_LoopField)
      }
      ary_addr.Insert(addr)
    }
    FileEncoding , UTF-8

    ; 最寄り番地を得る
    min_distance=-1
    retval=
    for i, v in ary_addr {
        if (InStr(v[1], area)) {
            distance := Sqrt(Exp(abs(xcoord - v[4])) + Exp(abs(zcoord - v[5])))
            ;OutputDebug, % "[" i "]" distance
            if (min_distance == -1 || min_distance > distance) {
                ;OutputDebug, % i " " v[2] " " v[3] " is Nearest!"
                min_distance := distance
                retval := v[2] "_" v[3] ; 最寄りアルター
            }
        }
    }
    return retval
}

getxl() {
    Global Xl
    if (Xl) {
        return Xl
    }
    try {
        Xl := ComObjActive("Excel.Application")
    } catch {
        Xl := ComObjCreate("Excel.Application")
    }
    return Xl
}


Append_Excel(date, server, area, alter, address, xc, zc, text) {
    Global Xl, Excel_Filename

    if (!Xl) {
        Xl := getxl()
    }
    if (!Xl || !IsObject(Xl)) {
        return
    }

    ; パスが相対かチェック
    if (InStr(Excel_Filename, ":")) {
        fname := Excel_Filename
    } else {
        fname := % A_ScriptDir "\" Excel_Filename
    }
    ; ファイルを開く
    try {
        Workbook := Xl.Workbooks.Open(fname)
    } catch {
        MsgBox, Excelファイル' %fname% 'が見つかりません！
        return
    }
   ;Xl.Visible := True      ; for Debug

    ; 空いている行を探す
    cnt := 0
    while (Xl.Range("A" . A_Index).Value != "") {
        cnt++
    }
    inspos := cnt+1

    Loop, Parse, text, `n
    {
        if (strlen(A_LoopField) < 3) {
            continue
        }
        buf := Delete_Weapon_Creator(A_LoopField)
        parse_price_item(buf, price, item)
        Xl.Range("A" . inspos).Select
        Xl.Range("A" . inspos).Value := date
        Xl.Range("B" . inspos).Value := server
        Xl.Range("C" . inspos).Value := area
        Xl.Range("D" . inspos).Value := alter
        Xl.Range("E" . inspos).Value := address
        Xl.Range("F" . inspos).Value := xc
        Xl.Range("G" . inspos).Value := zc
        Xl.Range("H" . inspos).Value := price
        Xl.Range("I" . inspos).Value := item
        inspos++
    }
    Workbook.Save()
    Workbook.Close()
    return
}

; MG商品の銘と思しき箇所を削る
Delete_Weapon_Creator(str_in) {
    if (InStr(str_in, "テレポート")) {
        return str_in
    }
    if (InStr(str_in, "悟り")) {
        return str_in
    }
    if (InStr(str_in, "賢者")) {
        return str_in
    }
    if (InStr(str_in, "時の石")) {
        return str_in
    }
    if (InStr(str_in, "装備")) {
        return str_in
    }
    if (InStr(str_in, "地図")) {
        return str_in
    }
    if (InStr(str_in, "ノアゲート")) {
        return str_in
    }
    if (InStr(str_in, "アニマル ケイジ")) {
        return str_in
    }
    if (InStr(str_in, "古文書")) {
        return str_in
    }
    if (InStr(str_in, "魚拓")) {
        return str_in
    }
    if (InStr(str_in, "ホムンクルス人形")) {
        return str_in
    }
    if (InStr(str_in, "レシピ ノート")) {
        return str_in
    }
    if (InStr(str_in, "ハウスキッ")) {
        return str_in
    }
    ret := str_in
;   ret := RegExReplace(ret, "[<({]+[!-~ ｜ぁ-ーァ-ヶァ-ヴー一-龠]+[>)}]+", "【製作者銘削除】") ; 効き過ぎる
    ret := RegExReplace(ret, "[<]+[!-~ ｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+[>}]+", "【MG品】")
    return ret
}

parse_price_item(text, ByRef price, ByRef item) {
    pos := RegExMatch(text, "P)[ ]*Gold[\] ]*", mlen)
    if (!pos) {
        price := 0
        item := text
        return
    }
    item := SubStr(text, pos+mlen)
    item := Trim(item)

    pbuf := SubStr(text, 1, pos)
    pbuf := RegExReplace(pbuf, "^IJ", "[4")
    pbuf := RegExReplace(pbuf, "M", "4")
    pbuf := RegExReplace(pbuf, "^∞", "[9")
    pbuf := RegExReplace(pbuf, "@A", "@4")
    pbuf := RegExReplace(pbuf, "郎", "@3")
    pbuf := RegExReplace(pbuf, "G", "6")
    ; 数値だけ抜き出す(数字以外を削除)
    pbuf := RegExReplace(pbuf, "[^0-9]", "")

    if (pbuf=) {
        pbuf = 0
    }
    price := pbuf
}

server_to_int(svr) {
    if (svr == "EMERALD") {
        return 1
    }
    if (svr == "DIAMOND") {
        return 2
    }
    if (svr == "PEARL") {
        return 3
    }
    return 0
}

area_to_int(area) {
    if (Instr(area, "ソレス")) {
        return 1
    }
    if (Instr(area, "ユグ")) {
        return 2
    }
    if (Instr(area, "北東エリア")) {
        return 3
    }
    if (Instr(area, "南エリア")) {
        return 4
    }
    if (Instr(area, "西エリア")) {
        return 5
    }
    if (Instr(area, "シス")) {
        return 6
    }
    return 0
}

alter_to_int(area, alter) {
    if (area == 6) {
        if (alter == "A-1") {
            return 1
        }
        if (alter == "A-2") {
            return 2
        }
        if (alter == "B-1") {
            return 3
        }
        if (alter == "B-2") {
            return 4
        }
        if (alter == "B-3") {
            return 5
        }
        if (alter == "C-1") {
            return 6
        }
        if (alter == "C-2") {
            return 7
        }
        if (alter == "C-3") {
            return 8
        }
        if (alter == "D-1") {
            return 9
        }
        if (alter == "D-2") {
            return 10
        }
        if (alter == "E-1") {
            return 11
        }
        if (alter == "E-2") {
            return 12
        }
        if (alter == "F-1") {
            return 13
        }
        if (alter == "F-2") {
            return 14
        }
        if (alter == "G-1") {
            return 15
        }
    }
    if (alter == "メイン") {
        return 0
    }
    return alter
}

post_to_gae(server, area, alter, address, xc, zc, item) {
    Global POST_URL, RequestHdr, HTTP_Options

    ; DBに入れたらあかん文字
    item := RegExReplace(item, "'", "")
    item := RegExReplace(item, "`;", "")
    item := RegExReplace(item, "&", "＆")

    ; 銘を削る
    item := RegExReplace(item, "【MG品】", "")
    ; 耐久度を削る(可能ならば)
    item := RegExReplace(item, "\([0-9]+/[0-9]+\)", "")
    item := RegExReplace(item, "[ ]+$", "")

    item := Trim(item)          ; 左右の空白を削る
    item := UriEncode(item)

;   PostData = server=%server%&area=%area%&alter=%alter%&address=%address%&xc=%xc%&zc=%zc%&price=%price%&item=%item%&
    PostData = tick=%A_TickCount%&server=%server%&area=%area%&alter=%alter%&address=%address%&xc=%xc%&zc=%zc%&records=%item%&

    pwhr := ComObjCreate("WinHttp.WinHttpRequest.5.1") ; Create WinHttpRequest object
    req := "http://moe-vendor-search.appspot.com/PostAHK?" ; 本番環境
;   req := "http://localhost:8080/PostAHK?"    ; 家の - デバッグ用
    req .= PostData
    dout("PostData: " req)

    pwhr.Open("POST", req) ; Initialize an HTTP request.
    pwhr.Send()
    text := pwhr.ResponseText ; get HTML
    if (InStr(text, "MVC_Insert_to_DB_OK")) {
        ; 正常終了
        if (ChkDebug) {
            dout(text)
            FileAppend, %text%, gae_result.html
            FileAppend, <HR>, gae_result.html
        }
    } else {
        ; 何かしらエラー
        dout(text)
        FileAppend, %text%, gae_result.html
        FileAppend, <HR>, gae_result.html
    }
}

; modified from jackieku's code (http://www.autohotkey.com/forum/post-310959.html#310959)
UriEncode(Uri, Enc = "UTF-8") {
	StrPutVar2(Uri, Var, Enc)
	f := A_FormatInteger
	SetFormat, IntegerFast, H
	Loop
	{
		Code := NumGet(Var, A_Index - 1, "UChar")
		If (!Code)
			Break
		If (Code >= 0x30 && Code <= 0x39 ; 0-9
			|| Code >= 0x41 && Code <= 0x5A ; A-Z
			|| Code >= 0x61 && Code <= 0x7A) ; a-z
			Res .= Chr(Code)
		Else
			Res .= "%" . SubStr(Code + 0x100, -1)
	}
	SetFormat, IntegerFast, %f%
	Return, Res
}

UriDecode(Uri, Enc = "UTF-8") {
	Pos := 1
	Loop
	{
		Pos := RegExMatch(Uri, "i)(?:%[\da-f]{2})+", Code, Pos++)
		If (Pos = 0)
			Break
		VarSetCapacity(Var, StrLen(Code) // 3, 0)
		StringTrimLeft, Code, Code, 1
		Loop, Parse, Code, `%
			NumPut("0x" . A_LoopField, Var, A_Index - 1, "UChar")
		StringReplace, Uri, Uri, `%%Code%, % StrGet(&Var, Enc), All
	}
	Return, Uri
}

StrPutVar2(Str, ByRef Var, Enc = "") {
	Len := StrPut(Str, Enc) * (Enc = "UTF-16" || Enc = "CP1200" ? 2 : 1)
	VarSetCapacity(Var, Len, 0)
	Return, StrPut(Str, &Var, Enc)
}
